package com.joyoung.sdk.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.joyoung.sdk.info.BaseRequesRes;
import com.joyoung.sdk.info.Device;
import com.joyoung.sdk.interface_sdk.CallBack;
import com.joyoung.sdk.interface_sdk.ChangeDevCallBack;
import com.joyoung.sdk.interface_sdk.CommandCallBack;
import com.joyoung.sdk.config.Cons_Sdk;
import com.joyoung.sdk.utils.JyHttp;
import com.joyoung.sdk.utils.URLGenerateUtil;
import com.joyoung.sdk.utils.encryptdecryptutil.XXTea;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * Created by Joyoung on 2016/5/24.
 */
public class JoyounglinkServers extends Service {
    private static final String TAG = JoyounglinkServers.class.getName();

    private String host;
    private String port;
    private String userName;
    private String passWord;
    private MqttClient client;
    private String myTopic;
    private String topic;
    private MqttConnectOptions options;
    private ExecutorService executorService;
    private ScheduledExecutorService scheduledExecutorService;
    private CommandCallBack mCommandCallBack;
    private CallBack callBack;
    private ChangeDevCallBack changeDevCallBack;
    private static final int CONNECT = 2;
    private static final int RESTART_CONNECT = 3;
    private static final int MQTTDATA = 5;
    private static final int RESTART_CONNECT_MQTTDATA = 10;
    private static int CONNECTTIME = 10;
    private boolean isRConnect = true;

    private MyMQTTHandler mQttHandler;


    /***
     * MQTT返回信息的回调
     *
     * @param commandCallBack
     */
    public void setOnMqttCallback(CommandCallBack commandCallBack) {
        this.mCommandCallBack = commandCallBack;
    }

    /***
     * MQTT连接成功或失败的回调
     *
     * @param callback
     */
    public void setCallback(CallBack callback) {
        this.callBack = callback;
    }

    public void setChangeDevCallBack(ChangeDevCallBack changeDevCallBack){
        this.changeDevCallBack=changeDevCallBack;
    }

    @Override
    public IBinder onBind(Intent intent) {

        return new MyBind();
    }

    /***
     *返回一个Service的实例
     *
     */
    public class MyBind extends Binder {
        public JoyounglinkServers getServers() {
            return JoyounglinkServers.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate");
        if (Cons_Sdk.clientId.equals("1")) {
            Cons_Sdk.clientId = UUID.randomUUID().toString();
        }
        executorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService = Executors.newScheduledThreadPool(3);
        initMqtt();

    }

    /***
     * 订阅主题
     *
     * @param devTypeId 设备类型
     * @param devID     设备ID
     */
    public void subscription(String devTypeId, String devID) {
        Log.e("订阅：", devTypeId + "----" + devID);
        try {
            myTopic = "/jy/app/" + devTypeId + "/ctrlResp/" + devID;
            topic = "/jy/app/" + devTypeId + "/devInfo/" + devID;
            if (client != null) {
                client.subscribe(new String[]{myTopic, topic}, new int[]{0, 0});
                Log.e("订阅主题", myTopic);
                Log.e("订阅主题", topic);
                changeDevCallBack.onSuccess();

            } else {
                changeDevCallBack.onError();
                mHandler.sendEmptyMessage(RESTART_CONNECT_MQTTDATA);
            }

        } catch (MqttException e) {
            e.printStackTrace();
            Log.e("msg", "订阅失败");
        }
    }

    /***
     * 解除订阅主题，在重新订阅之前必须解除订阅
     */
    public void unSubscription() {
        try {
            if (client != null && myTopic != null && topic != null) {
                client.unsubscribe(new String[]{myTopic, topic});
                Log.e("解除订阅主题", myTopic);
                Log.e("解除订阅主题", topic);
            } else {
                mHandler.sendEmptyMessage(RESTART_CONNECT_MQTTDATA);
            }
        } catch (MqttException e) {
            Log.e("解除订阅主题失败", e.getMessage());
            e.printStackTrace();
        }
    }

    private void initMqtt() {
        try {
            getMQTT();
            Log.e(TAG, "initMqtt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void getMQTT() {
        String url = URLGenerateUtil.urlGenerateCMS(Cons_Sdk.BASE_GETMQTTADDRESS, null);
        JyHttp.getInstance().getMqtt(this, url, Cons_Sdk.sslName, new Callback() {


            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("mqtt地址", "获取失败");
                createHandler();
            }

            @Override
            public void onResponse(Call call, Response response) {
                Log.e("mqtt", "onResponse: " + response.message());
                Gson gson = new Gson();

                try {
                    String result = response.body().string();
                    if (result != null && !result.equals("")) {
                        BaseRequesRes<String> res = gson.fromJson(result, new TypeToken<BaseRequesRes<String>>() {
                        }.getType());
                        if (res != null && res.getCode() == 0 && res.getData() != null) {
                            String data = new String((XXTea.decrypt(Hex.decodeHex(res.getData().toCharArray()), Cons_Sdk.dataKey.getBytes())));
                            Log.e("mqtt地址", data);
                            BaseRequesRes<Device> basedata = gson.fromJson(data, new TypeToken<BaseRequesRes<Device>>() {
                            }.getType());
                            if (basedata.getCode() == 0) {
                                Cons_Sdk.device = basedata.getData();
                                if (mQttHandler == null) {
                                    Looper.prepare();
                                    mQttHandler = new MyMQTTHandler();
                                    mQttHandler.sendEmptyMessage(MQTTDATA);
                                    Looper.loop();
                                } else {
                                    mQttHandler.sendEmptyMessage(MQTTDATA);
                                }

                            } else {
                                createHandler();
                            }
                        } else {
                            Log.e("mqtt地址", "获取失败" + res.getData());
                            createHandler();
                        }
                    } else {
                        Log.e("mqtt地址", "获取失败" + result);
                        createHandler();
                    }
                } catch (IOException e) {
                    Log.e("mqtt地址", "获取失败IOException");
                    createHandler();
                } catch (DecoderException e) {
                    Log.e("mqtt地址", "获取失败DecoderException");
                    createHandler();
                }
            }
        });

    }


    private void createHandler() {
        if (mQttHandler == null) {
            Looper.prepare();
            mQttHandler = new MyMQTTHandler();
            mQttHandler.sendEmptyMessage(RESTART_CONNECT);
            Looper.loop();
        } else {
            mQttHandler.sendEmptyMessage(RESTART_CONNECT);
        }

    }

    private class MyMQTTHandler extends Handler {


        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MQTTDATA:
                    init();
                    break;
                case RESTART_CONNECT:
                    try {
                        Thread.sleep(CONNECTTIME * 1000);
                        CONNECTTIME += CONNECTTIME;
                        initMqtt();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    break;

            }
        }
    }


    private void init() {
        Log.e(TAG, "init");
        userName = Cons_Sdk.device.getUser();
        passWord = Cons_Sdk.device.getPass();
        host = "tcp://" + Cons_Sdk.device.getAddr();
        port = Cons_Sdk.device.getPort();
        if (TextUtils.isEmpty(userName) || userName.equals("") || TextUtils.isEmpty(passWord) || passWord.equals("") || TextUtils.isEmpty(host) || host.equals("") || TextUtils.isEmpty(port) || port.equals("")) {
            if (mQttHandler == null) {
                Looper.prepare();
                mQttHandler = new MyMQTTHandler();
                mQttHandler.sendEmptyMessage(RESTART_CONNECT);
                Looper.loop();
            } else {
                mQttHandler.sendEmptyMessage(RESTART_CONNECT);
            }

        } else {
            host = host + ":" + port;
            try {
                client = new MqttClient(host, Cons_Sdk.clientId, new MemoryPersistence());
            } catch (MqttException e) {
                mHandler.sendEmptyMessage(RESTART_CONNECT_MQTTDATA);
                return;
            }

            setMqttConnectOptions();

            connect();
        }


    }

    /***
     * mqtt连接设置
     *
     * @param
     */
    private void setMqttConnectOptions() {
        //MQTT的连接设置
        options = new MqttConnectOptions();
        //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
        options.setCleanSession(false);
        //设置连接的用户名
        options.setUserName(userName);
        //设置连接的密码
        options.setPassword(passWord.toCharArray());
        // 设置超时时间 单位为秒
        options.setConnectionTimeout(10);
        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
        options.setKeepAliveInterval(20);
    }


    private MqttCallback callback = new MqttCallback() {
        @Override
        public void connectionLost(Throwable cause) {
            mCommandCallBack.connectionLost(cause.getMessage());
        }

        @Override
        public void messageArrived(String topic, MqttMessage messages) {
            String key = Cons_Sdk.decryptKey;
            Log.e("decryptKey", key + "");
            try {
                if (key != null && !key.equals("")) {
                    String message = new String(XXTea.decrypt(messages.getPayload(), key.getBytes()));
                    Log.e("topic", topic + "");
                    Log.e("message", message + "");
                    mCommandCallBack.messageArrived(topic, message);
                }
            } catch (Throwable throwable) {
                String str = throwable.getMessage();
                Log.e("error is Log", str);
            }

        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            Log.e("msg", "publish");
            mCommandCallBack.deliveryComplete(token.getResponse().toString());
        }
    };
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CONNECT:
                    callBack.onSuccess();
                    if (isRConnect) {
                        startReconnection();
                        isRConnect = false;
                    }
                    break;
                case RESTART_CONNECT:
                    if (isRConnect) {
                        startReconnection();
                        isRConnect = false;
                    }
                    callBack.onError();
                    break;
                case RESTART_CONNECT_MQTTDATA:
                    initMqtt();
                    break;
            }

        }

    };

    /**
     * 连接
     */
    private void connect() {
        Log.e(TAG, "connect");
        executorService.execute(runnable);
    }

    /***
     * 10秒判断连接的线程
     */
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (client != null) {
                    client.connect(options);
                    if (client.isConnected()) {
                        client.setCallback(callback);
                        Message msg = new Message();
                        msg.what = CONNECT;
                        mHandler.sendMessage(msg);
                    } else {
                        connect();
                    }
                } else {
                    mHandler.sendEmptyMessage(RESTART_CONNECT_MQTTDATA);
                }


            } catch (MqttException e) {
                e.printStackTrace();
                Message msg = new Message();
                msg.what = RESTART_CONNECT;
                mHandler.sendMessage(msg);
            }
        }
    };

    /**
     * 重新连接
     */
    private void startReconnection() {
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                if (client == null || !client.isConnected()) {
                    if (client == null) {
                        mHandler.sendEmptyMessage(RESTART_CONNECT_MQTTDATA);
                    } else {
                        connect();
                    }
                } else if (client != null) {
                    Log.e("msg", "mqtt连接成功");
                }
            }
        }, 1 * 1000, 30 * 1000, TimeUnit.MILLISECONDS);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        try {
            if (scheduledExecutorService != null)
                scheduledExecutorService.shutdown();
            if (executorService != null)
                executorService.shutdown();
            if (myTopic == null || topic == null) {
            } else {
                unSubscription();
            }
            if (mHandler != null && runnable != null)
                mHandler.removeCallbacks(runnable);
            if (mQttHandler != null)
                mQttHandler.removeCallbacks(null);
            if (null != client && client.isConnected()) {
                client.disconnect();
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }

    }
}
